using System;
using System.IO;
using System.Collections.Generic;

namespace tvgrabau
{
	public class OutputManager
	{
		private List<Programme> p;
		public static string BaseIconLocation = "http://medati.org/projects/tvgrabau/tvicons/";
	
		public OutputManager(List<Programme> pl)
		{
			p = pl;
		}
		
		public void WriteOutput(string filename)
		{
			/*
				Really couldn't care less right now..
				Going to use my own QuickXmlWriter class, instead of an XmlWriter.. :)
			*/
					
			// Initialise our streams for use
			QuickXml.QuickXmlWriter qxml = new QuickXml.QuickXmlWriter(filename);
			qxml.IndentationWidth = 1;
			qxml.IndentationCharacter = '\t';
			
			qxml.WriteDeclaration();
			
			List<QuickXml.QuickXmlAttribute> al = new List<QuickXml.QuickXmlAttribute>();
			al.Add(new QuickXml.QuickXmlAttribute("source-info-name", "HWW Limited"));
			al.Add(new QuickXml.QuickXmlAttribute("source-info-url", "http://www.yourtv.com.au/"));
			al.Add(new QuickXml.QuickXmlAttribute("generator-info-name", "tvgrabau v"+System.Reflection.Assembly.GetExecutingAssembly().GetName().Version));
			al.Add(new QuickXml.QuickXmlAttribute("generator-info-url", "http://mediati.org/projects/tvgrabau/"));
			qxml.StartTag("tv", al, null, true);
			
			foreach(GrabberOptions.ChannelMap cm in MainClass.options.ChannelMaps)
			{
				List<QuickXml.QuickXmlAttribute> ac = new List<QuickXml.QuickXmlAttribute>();
				ac.Add(new QuickXml.QuickXmlAttribute("id", cm.XMLID));
				ac.Add(new QuickXml.QuickXmlAttribute("callsign", cm.Callsign));
				ac.Add(new QuickXml.QuickXmlAttribute("icon", BaseIconLocation + cm.Name.ToLower() + ".png")); 
				qxml.StartTag("channel", ac, null, true);
				qxml.StartTag("display-name", cm.Name);
				qxml.EndTag();
				qxml.EndTag();
			}
					
			int x = 0;
			while (x < p.Count) 
			{
				List<QuickXml.QuickXmlAttribute> ac = new List<QuickXml.QuickXmlAttribute>();
				string ChannelAttribute = "";
				foreach(GrabberOptions.ChannelMap cm in MainClass.options.ChannelMaps)
				{
					if (cm.Name == p[x].ChannelName)
					{
						ChannelAttribute = cm.XMLID;
					}
				}
				
				
				if (ChannelAttribute != "")
				{
					qxml.WriteNewLine();
					ac.Add(new QuickXml.QuickXmlAttribute("channel", ChannelAttribute));					
					
					ac.Add(new QuickXml.QuickXmlAttribute("start", p[x].TimeStart.ToString("yyyyMMddHHmm zzzz")));
					ac.Add(new QuickXml.QuickXmlAttribute("stop", p[x].TimeEnd.ToString("yyyyMMddHHmm zzzz")));
					
					if (p[x].ID != 0)
					{
						qxml.WriteComment(p[x].ID.ToString());
					}
					
					qxml.StartTag("programme", ac, null, true);
					qxml.StartTag("title", p[x].Title);
					qxml.EndTag();
					if (p[x].EpisodeName != null)
					{
						qxml.StartTag("sub-title", p[x].EpisodeName);
						qxml.EndTag();
					}
					if (p[x].Description != null)
					{
						if (p[x].Description.Trim().Length > 0)
						{
							qxml.StartTag("desc", p[x].Description);
							qxml.EndTag();
						}
					}
					if (p[x].Classification != null)
					{
						if (p[x].Classification.Length > 0)
						{
							qxml.StartTag("rating", true);
							qxml.StartTag("value", p[x].Classification);
							qxml.EndTag();
							qxml.EndTag();
						}
					}
					if (p[x].Country != null)
					{
						qxml.StartTag("country", p[x].Country);
						qxml.EndTag();
					}
					if (p[x].HDTV || p[x].Widescreen)
					{
						qxml.StartTag("video", true);
						if (p[x].Widescreen)
						{
							qxml.StartTag("aspect", "16:9");
							qxml.EndTag();
						}
						if (p[x].HDTV)
						{
							qxml.StartTag("quality", "HDTV");
							qxml.EndTag();
						}
						qxml.EndTag();
					}
					if (p[x].Premiere)
					{
						qxml.StartTag("premiere");
					}
					if (p[x].Repeat)
					{
						qxml.StartTag("previously-shown");
					}
					if (p[x].Final)
					{
						qxml.StartTag("last-chance");
					}
					if (p[x].Teletext)
					{
						qxml.StartTag("subtitles", new QuickXml.QuickXmlAttribute("type", "teletext"), null);
					}
					if (p[x].Type == ProgrammeType.Movie)
					{
						qxml.StartTag("category", "movie");
						qxml.EndTag();
					}
					else if (p[x].Type == ProgrammeType.Series)
					{
						qxml.StartTag("category", "series");
						qxml.EndTag();
					}
					else if (p[x].Type == ProgrammeType.Sports)
					{
						qxml.StartTag("category", "sports");
						qxml.EndTag();
					}
					else
					{
						qxml.StartTag("category", "tvshow");
						qxml.EndTag();
					}
					if (p[x].Category != null)
					{
						char[] splitCat = { '/' };
						string[] splitStr = p[x].Category.Split(splitCat);
						foreach (string s in splitStr)
						{
							qxml.StartTag("category", s);
							qxml.EndTag();
						}
					}
					if (p[x].Final)
					{
						qxml.StartTag("final");
						qxml.StartTag("last-chance");
					}
					if (p[x].Year != null)
					{
						qxml.StartTag("date", p[x].Year);
						qxml.EndTag();
					}
					if (p[x].Cast != null)
					{
						qxml.StartTag("credits", true);
						char[] splitCast = { ',' };
						string[] splitStr = p[x].Cast.Split(splitCast);
						foreach (string s in splitStr)
						{
							string i = s.Trim();
							qxml.StartTag("actor", i);
							qxml.EndTag();
						}
						qxml.EndTag();
					}
					if (p[x].Score != null)
					{
						qxml.StartTag("star-rating", true);
						qxml.StartTag("value", p[x].Score.ToString() + "/10");
						qxml.EndTag();
						qxml.EndTag();
					}
					
					// End <programme> tag..
					qxml.EndTag();
				}
				x++;
			}
			
			// End the main <tv> tag..
			qxml.EndTag();
			
			// All done writing, now - flush and close
			qxml.WriteClose();			
		}
		
		public static class QuickXml
		{
			public class QuickXmlWriter
			{
			
				private int indentCount = 0;
				private string indentString = "  ";	// Default 2 spaces
				private int indentLength = 2;	// 2 spaces.. :)
				private char indentChar = ' ';	// Defaults to space
				
				private List<string> tagStack = new List<string>();
				private TextWriter tw;
				private string ts = "";
				private bool CanWrite = false;
				
				private const string DefaultDeclarationVersion = "1.0";
				private const string DefaultDeclarationEncoding = "UTF-8";
				
				public QuickXmlWriter(string XmlFilePath)
				{
					bool WasErrors = false;
					try
					{
						tw = new StreamWriter(XmlFilePath);
					}
					catch (System.Exception)
					{
						WasErrors = true;
					}
					
					if (!WasErrors)
					{
						CanWrite = true;
					}
					
				}
				
				
				public char IndentationCharacter
				{
					set
					{
						indentChar = value;
						resetIndentString();
					}
					get
					{
						return indentChar;
					}
				}
				
				public int IndentationWidth
				{
					set
					{
						indentLength = value;
						resetIndentString();
					}
					get
					{
						return indentLength;
					}
				}
				
				public string Body
				{
				    get
				    {
				        return ts;
				    }
				}
				
				private void resetIndentString()
				{
					string t = "";
					int x = 0;
					
					while (x < indentLength)
					{
						t += indentChar.ToString();
						x++;
					}
					
					indentString = t;
				}
				
				public void WriteDeclaration()
				{
					// Just write the defaults.. :)
					WriteDeclaration(DefaultDeclarationVersion, DefaultDeclarationEncoding);
				}
				
				public void WriteClose()
				{
					tw.Flush();
					tw.Close();
					CanWrite = false;
				}
				
				public void Flush()
				{
					tw.Flush();
				}
				
				public void WriteNewLine()
				{
					tw.WriteLine();
					ts += "\n";
				}
				
				public void WriteComment(string comment)
				{
					if (CanWrite)
					{
						string Indent = "";
						int y = 0;
						while (y < indentCount)
						{
							Indent += indentString;
							y++;
						}
						
						tw.WriteLine(Indent + "<!-- " + comment + " -->");
						ts += (Indent + "<!-- " + comment + " -->") + "\n";
					}
					else
					{
						throw new System.InvalidOperationException("Cannot complete operation: There were errors when trying to access the file.");
					}
				}
				
				public void StartTag(string TagName, string Value)
				{
					StartTag(TagName, null, Value, false);
				}
				
				public void StartTag(string TagName)
				{
					StartTag(TagName, null, null, false);
				}
				
				public void StartTag(string TagName, bool LeaveOpen)
				{
					StartTag(TagName, null, null, LeaveOpen);
				}
				
				
				public void StartTag(string TagName, QuickXml.QuickXmlAttribute Attribute, string Value)
				{
					List<QuickXml.QuickXmlAttribute> ac = new List<QuickXml.QuickXmlAttribute>(1);
					ac.Add(Attribute);
					StartTag(TagName, ac, Value, false);
				}
				
				public void StartTag(string TagName, List<QuickXml.QuickXmlAttribute> Attributes, string Value)
				{
					StartTag(TagName, Attributes, Value, false);
				}
				
				public void StartTag(string TagName, List<QuickXml.QuickXmlAttribute> Attributes, string Value, bool LeaveOpen)
				{
					if (CanWrite)
					{
						string AttributeString = "";
						string Indent = "";
					
						if (Attributes != null)
						{
							foreach(QuickXml.QuickXmlAttribute a in Attributes)
							{
								AttributeString += a.Key + "=\"" + a.Value + "\" ";
							}
							
							if (AttributeString.Length > 0)
							{
								AttributeString = AttributeString.Remove(AttributeString.Length-1, 1);
							}
						}
						
						int y = 0;
						while (y < indentCount)
						{
							Indent += indentString;
							y++;
						}
						
						tw.Write(Indent + "<"+TagName);
						ts += (Indent + "<"+TagName);
						if (AttributeString != "")
						{
							tw.Write(" "+AttributeString);
							ts += (" "+AttributeString);
						}
						
						if (Value == null && LeaveOpen == false)
						{
							tw.WriteLine("/>");
							ts += ("/>") + '\n';
						}
						else if (Value != null && LeaveOpen == false)
						{
							/*
							if (Value.Length > 80)
							{
								tw.WriteLine(">");
								Indent += indentString;
								if (Value != null)
								{
									tw.WriteLine(Indent + Value);
								}
								tagStack.Add(TagName);
								indentCount++;
							}
							else
							{
								tw.Write(">");
								tw.Write(Value);
								tagStack.Add(TagName + "\"");
							}*/
							
							//Indent += indentString;
							tw.Write(">");
							ts += ">";
							tw.Write(Value);
							ts += Value;
							tagStack.Add(TagName + "\"");
							//indentCount++;
						}
						else
						{
							tw.WriteLine(">");
							ts += ">\n";
							Indent += indentString;
							if (Value != null && Value != "")
							{
								tw.WriteLine(Indent + Value);
								ts += Indent + Value + "\n";
							}
							tagStack.Add(TagName);
							indentCount++;
						}
					}
					else
					{
						throw new System.InvalidOperationException("Cannot complete operation: There were errors when trying to access the file.");
					}
				}
				
				
				public void EndTag()
				{
					if (CanWrite)
					{
						int LastTag = tagStack.Count - 1;
						string TagName = (string)tagStack[LastTag];
						string Indent = "";
						int y = 0;
						while (y < indentCount - 1)
						{
							Indent += indentString;
							y++;
						}
						
						if (TagName.EndsWith("\""))
						{
						    string str = "</"+TagName.Remove(TagName.Length - 1, 1)+">";
							tw.WriteLine(str);
							ts += (str) + "\n";
						}
						else
						{
							tw.WriteLine(Indent + "</"+TagName+">");
							ts += (Indent + "</"+TagName+">") + "\n";
							indentCount--;
						}
						tagStack.RemoveAt(LastTag);
					}
					else
					{
						throw new System.InvalidOperationException("Cannot complete operation: There were errors when trying to access the file.");
					}
				}
				
				public void WriteDeclaration(string encoding)
				{
					WriteDeclaration(DefaultDeclarationVersion, encoding);
				}
				
				public void WriteDeclaration(string version, string encoding)
				{
					if (CanWrite)
					{
						tw.WriteLine("<?xml version=\""+version+"\" encoding=\""+encoding+"\" ?>"+tw.NewLine);
						ts += ("<?xml version=\""+version+"\" encoding=\""+encoding+"\" ?>"+tw.NewLine) + "\n";
					}
					else
					{
						throw new System.InvalidOperationException("Cannot complete operation: There were errors when trying to access the file.");
					}
				}
			}
			
			public class QuickXmlAttribute
			{
				private string KeyP = "";
				public string Value = "";
				
				public string Key
				{
					get
					{
						return KeyP;
					}
				}
				
				public QuickXmlAttribute(string k, string v)
				{
					KeyP = k;
					Value = v;
				}
				
				public QuickXmlAttribute(string k)
				{
					KeyP = k;
				}
			}
		
		}	// End QuickXml static class
	}
}
